package levels

import (
	"context"
	"fmt"

	"mall/common/ctxdatax"
	"mall/common/resultx"
	"mall/service/backend/common/utils/pointy"
	"mall/service/forum/api/internal/lib/userrank"
	"mall/service/forum/api/internal/lib/usertask"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/user/rpc/userclient"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetUserLevelListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetUserLevelListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserLevelListLogic {
	return &GetUserLevelListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetUserLevelListLogic) GetUserLevelList(req *types.UserLevelListReq) (resp *types.UserLevelListInfo, err error) {
	userId := ctxdatax.GetUserId(l.ctx)
	if userId == 0 {
		return nil, resultx.NewErrCode(resultx.TOKEN_EXPIRE_ERROR)
	}

	res, err := l.svcCtx.UserRpc.GetUserTaskStatistic(l.ctx, &userclient.CurrentUserReq{
		UserId: pointy.GetPointer(userId),
	})
	if err != nil {
		return nil, err
	}

	// logrus.Info(fmt.Sprintf("GetUserLevelList UserTaskStatistic: %+v", res))

	var userLevel uint64
	if res.Level != nil && *res.Level > 0 {
		userLevel = uint64(*res.Level)
	}

	resp = &types.UserLevelListInfo{
		Level: res.Level,
	}

	taskIdMap := make(map[uint64]string)
	userTaskList, err := l.getUserTaskList(userId)
	if err != nil {
		logrus.Info(fmt.Sprintf("GetUserLevelList getUserRankList err: %+v", err))
	} else {
		for _, v := range userTaskList {
			if v.Id != nil && v.Slug != nil {
				taskIdMap[*v.Id] = *v.Slug
			}
			resp.TaskList = append(resp.TaskList, v)
		}
	}

	userRankList, err := l.getUserRankList(userId)
	if err != nil {
		logrus.Info(fmt.Sprintf("GetUserLevelList getUserRankList err: %+v", err))
	} else {
		var isNext int = 0
		for _, v := range userRankList {
			if isNext == 1 {
				var threshold *uint32
				var count uint32
				if len(v.Restrictions) > 0 {
					threshold = pointy.GetPointer(uint32(len(v.Restrictions)))
					if res.UserTaskStatisticMap != nil {
						for idx, rv := range v.Restrictions {
							if rv.TaskId != nil && *rv.TaskId > 0 && rv.Threshold != nil && *rv.Threshold > 0 {
								if slug, ok := taskIdMap[*rv.TaskId]; ok {
									if cnt, ok := res.UserTaskStatisticMap[slug]; ok {
										if cnt >= *rv.Threshold {
											count += 1
											v.Restrictions[idx].TaskFulfilled = true
										}
										v.Restrictions[idx].TaskProgress = pointy.GetPointer(fmt.Sprintf("%d/%d", cnt, *rv.Threshold))
									}
								}
							}
						}
					}
				}
				v.NextThreshold = threshold
				v.NextCount = count
			} else {
				var threshold *uint32
				var count uint32
				if len(v.Restrictions) > 0 {
					threshold = pointy.GetPointer(uint32(len(v.Restrictions)))
					count = uint32(len(v.Restrictions))
				}
				v.NextThreshold = threshold
				v.NextCount = count
			}
			if v.Id != nil && *v.Id == userLevel {
				isNext = 1
			}
			resp.List = append(resp.List, v)
		}
	}

	return resp, nil
}

func (l *GetUserLevelListLogic) getUserRankList(userId uint64) (resp []*types.UserRankInfo, err error) {
	userRank := userrank.NewUserRank(l.ctx, l.svcCtx)

	return userRank.List(userId)
}

func (l *GetUserLevelListLogic) getUserTaskList(userId uint64) (resp []*types.UserTaskInfo, err error) {
	userTask := usertask.NewUserTask(l.ctx, l.svcCtx)

	return userTask.List(userId)
}
